﻿using AutoMapper;
using IOA.MES.Common;
using IOA.MES.DataAccess.Entity;
using IOA.MES.DataAccess.Enum;
using IOA.MES.DataAccess.VModel;
using IOA.MES.Log.Business;
using IOA.MES.Log.DataAccess.VModel;
using IOA.Utils;
using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IOA.MES.Business
{
    /// <summary>
    /// 拼柜管理（错误代码：129001）
    /// </summary>
    public class CabinetMgr
    {
        private Logger logger = LogManager.GetCurrentClassLogger();
        private MESContext mesDb = new MESContext("MES");

        /// <summary>
        /// 创建拼柜
        /// </summary>
        /// <param name="model"></param>
        public void CreateCabinet(VCabinet model)
        {
            var entity = mesDb.Cabinets.AsNoTracking().FirstOrDefault(_ => _.CabinetNo == model.CabinetNo && _.Status != CabinetStatus.UnCabinet && _.Valid);
            if (entity != null)
            {
                throw new MultiLanBizException(129001, model.CabinetNo);//当前柜号已存在，请更换其他柜号
            }
            entity = Mapper.Map<Cabinet>(model);
            entity.Status = CabinetStatus.Cabineting;
            entity.CreateTime = DateTime.Now;
            mesDb.Cabinets.Add(entity);
            mesDb.SaveChanges();
        }

        /// <summary>
        /// 拼柜
        /// </summary>
        /// <param name="model">柜子</param>
        /// <param name="packNos">包列表</param>
        public void CabinetPack(VCabinet model, List<string> packNos, out VCabinetCondition cabinetCondition)
        {
            cabinetCondition = null;
            packNos = packNos.Where(_ => !string.IsNullOrWhiteSpace(_)).Select(_ => _.ToUpper().Trim()).Distinct().ToList();
            var packs = mesDb.Packs.AsNoTracking().Where(_ => packNos.Contains(_.PackNo) && _.PackStatus == PackStatus.Normal && _.Valid).ToList();
            if (packNos.Any(no => !packs.Select(_ => _.PackNo.ToUpper()).Contains(no)))
            {
                throw new MultiLanBizException(129002, string.Join("、", packNos.Where(no => !packs.Select(_ => _.PackNo).Contains(no))));// $"下列打包编号不存在：
            }
            else if (packs.Any(_ => !string.IsNullOrWhiteSpace(_.CabinetNo) && !StringUtils.Equals(_.CabinetNo, model.CabinetNo)))
            {
                throw new MultiLanBizException(129007, string.Join("、", packs.Where(_ => !string.IsNullOrWhiteSpace(_.CabinetNo) && !StringUtils.Equals(_.CabinetNo, model.CabinetNo)).Select(_ => _.PackNo)));// $"下列包装已拼在其他柜中：
            }
            else if (packs.Any(_ => _.PackInspectStatus != PackInboundInspectStatus.Inspected))
            {
                throw new MultiLanBizException(129009, string.Join("、", packs.Where(_ => _.PackInspectStatus != PackInboundInspectStatus.Inspected).Select(_ => _.PackNo)));// $"下列包装没有通过入库检
            }

            var entity = mesDb.Cabinets.AsNoTracking().FirstOrDefault(_ => _.CabinetNo == model.CabinetNo && _.Status != CabinetStatus.UnCabinet && _.Valid);
            if (entity == null)
            {
                entity = Mapper.Map<Cabinet>(model);
                entity.WarehouseCode = packs.FirstOrDefault().WarehouseCode;
                entity.WarehouseName = packs.FirstOrDefault().WarehouseName;
                entity.ProductCode = packs.FirstOrDefault().ProductCode;
                entity.ProductName = packs.FirstOrDefault().ProductName;
                entity.ProductSpecs = packs.FirstOrDefault().ProductSpecs;
                entity.Status = CabinetStatus.Normal;
                entity.PackQuantity = packNos.Count;
                entity.CreateTime = DateTime.Now;

                entity.InnerOrderNo = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.InnerOrderNo;
                entity.OrderNo = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.OrderNo;
                entity.WorkOrderNo = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.WorkOrderNo;
                entity.NameplateModel = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.NameplateModel;
                entity.IVPowerLevel = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.IVPowerLevel ?? 0;
                entity.IVCurrentLevel = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.IVCurrentLevel;
                entity.QLevel = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.QLevel;
                entity.ComponentColor = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.ComponentColor;
                entity.JunBoxFactory = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.JunBoxFactory;
                entity.JunBoxSpecs = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.JunBoxSpecs;
                entity.BackPlanFactory = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.BackPlanFactory;
                entity.BackPlanSpecs = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.BackPlanSpecs;
                entity.AluFrameFactory = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.AluFrameFactory;
                entity.AluFrameSpecs = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.AluFrameSpecs;
                entity.BatteryFactory = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.BatteryFactory;
                entity.BatterySpecs = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.BatterySpecs;

                mesDb.Cabinets.Add(entity);

                var fstPack = packs.FirstOrDefault(p => StringUtils.Equals(p.PackNo, packNos.FirstOrDefault()));
                cabinetCondition = new CabinetConditionMgr().GetCabinetCondition(string.Empty, entity.WorkOrderNo, StringUtils.Equals(entity.QLevel, "Q1") ? QLevelCondition.Q1 : QLevelCondition.NotQ1);
            }
            else
            {
                var existPacks = mesDb.CabinetPacks.AsNoTracking().Where(_ => _.CabinetNo == entity.CabinetNo && _.Valid).ToList();
                packs = packs.Where(p => !existPacks.Select(_ => _.PackNo.ToUpper()).Contains(p.PackNo.ToUpper())).ToList();
                if (!packs.Any())
                {
                    return;
                }

                mesDb.Cabinets.Attach(entity);
                entity.PackQuantity = existPacks.Count + packs.Count;
                entity.ModifyBy = model.ModifyBy;
                entity.ModifyTime = DateTime.Now;

                if (!existPacks.Any())
                {
                    entity.WarehouseCode = packs.FirstOrDefault().WarehouseCode;
                    entity.WarehouseName = packs.FirstOrDefault().WarehouseName;
                    entity.ProductCode = packs.FirstOrDefault().ProductCode;
                    entity.ProductName = packs.FirstOrDefault().ProductName;
                    entity.ProductSpecs = packs.FirstOrDefault().ProductSpecs;

                    entity.InnerOrderNo = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.InnerOrderNo;
                    entity.OrderNo = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.OrderNo;
                    entity.WorkOrderNo = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.WorkOrderNo;
                    entity.NameplateModel = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.NameplateModel;
                    entity.IVPowerLevel = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.IVPowerLevel ?? 0;
                    entity.IVCurrentLevel = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.IVCurrentLevel;
                    entity.QLevel = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.QLevel;
                    entity.ComponentColor = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.ComponentColor;
                    entity.JunBoxFactory = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.JunBoxFactory;
                    entity.JunBoxSpecs = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.JunBoxSpecs;
                    entity.BackPlanFactory = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.BackPlanFactory;
                    entity.BackPlanSpecs = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.BackPlanSpecs;
                    entity.AluFrameFactory = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.AluFrameFactory;
                    entity.AluFrameSpecs = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.AluFrameSpecs;
                    entity.BatteryFactory = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.BatteryFactory;
                    entity.BatterySpecs = packs.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, packNos.FirstOrDefault()))?.BatterySpecs;
                }

                var fstPackNo = existPacks.Any() ? existPacks.OrderBy(_ => _.PkId).FirstOrDefault().PackNo : packs.FirstOrDefault().PackNo;
                var fstPack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == fstPackNo && _.PackStatus == PackStatus.Normal && _.Valid);
                cabinetCondition = new CabinetConditionMgr().GetCabinetCondition(string.Empty, fstPack.WorkOrderNo, StringUtils.Equals(fstPack.QLevel, "Q1") ? QLevelCondition.Q1 : QLevelCondition.NotQ1);
            }

            if (cabinetCondition == null)
            {
                throw new MultiLanBizException(129005, model.WorkOrderNo);//当前工单拼柜规则不存在：
            }

            var configStr = !string.IsNullOrWhiteSpace(cabinetCondition.WorkOrderNo) ? $"工单配置：{cabinetCondition.WorkOrderNo}" : $"订单配置：{cabinetCondition.OrderNo}";
            foreach (var pack in packs)
            {
                if (cabinetCondition.QuantityLimit.HasValue && cabinetCondition.QuantityLimit.Value < entity.PackQuantity)
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，满柜数量：{cabinetCondition.QuantityLimit.Value}/{entity.PackQuantity}");//拼柜规则不匹配，拼柜依据、箱号、参数差异分别为：
                }
                else if (cabinetCondition.OrderNoLimit && !StringUtils.Equals(entity.OrderNo, pack.OrderNo))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，订单号：{entity.OrderNo}/{pack.OrderNo}");//拼柜规则不匹配，拼柜依据、箱号、参数差异分别为：
                }
                else if (cabinetCondition.WorkOrderNoLimit && !StringUtils.Equals(entity.WorkOrderNo, pack.WorkOrderNo))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，工单号：{entity.WorkOrderNo}/{pack.WorkOrderNo}");
                }
                else if (cabinetCondition.DataPlate && !string.IsNullOrWhiteSpace(pack.NameplateModel) && !StringUtils.Equals(entity.NameplateModel, pack.NameplateModel))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，铭牌型号：{entity.NameplateModel}/{pack.NameplateModel}");
                }
                else if (cabinetCondition.RatedPower && pack.IVPowerLevel.HasValue && pack.IVPowerLevel.Value > 0 && entity.IVPowerLevel != pack.IVPowerLevel)
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，额定功率：{entity.IVPowerLevel}/{pack.IVPowerLevel}");
                }
                else if (cabinetCondition.ElectricGrade && !string.IsNullOrWhiteSpace(pack.IVCurrentLevel) && !StringUtils.Equals(entity.IVCurrentLevel, pack.IVCurrentLevel))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，电流档：{entity.IVCurrentLevel}/{pack.IVCurrentLevel}");
                }
                else if (cabinetCondition.CompGrade && !string.IsNullOrWhiteSpace(pack.QLevel) && !StringUtils.Equals(entity.QLevel, pack.QLevel))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，组件等级：{entity.QLevel}/{pack.QLevel}");
                }
                else if (cabinetCondition.CompColor && !string.IsNullOrWhiteSpace(pack.ComponentColor) && !StringUtils.Equals(entity.ComponentColor, pack.ComponentColor))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，组件颜色：{entity.ComponentColor}/{pack.ComponentColor}");
                }
                else if (cabinetCondition.JunBoxFactory && !string.IsNullOrWhiteSpace(pack.JunBoxFactory) && !StringUtils.Equals(entity.JunBoxFactory, pack.JunBoxFactory))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，接线盒厂家：{entity.JunBoxFactory}/{pack.JunBoxFactory}");
                }
                else if (cabinetCondition.JunBoxSpecs && !string.IsNullOrWhiteSpace(pack.JunBoxSpecs) && !StringUtils.Equals(entity.JunBoxSpecs, pack.JunBoxSpecs))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，接线盒规格：{entity.JunBoxSpecs}/{pack.JunBoxSpecs}");
                }
                else if (cabinetCondition.BackPlanFactory && !string.IsNullOrWhiteSpace(pack.BackPlanFactory) && !StringUtils.Equals(entity.BackPlanFactory, pack.BackPlanFactory))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，背板厂家：{entity.BackPlanFactory}/{pack.BackPlanFactory}");
                }
                else if (cabinetCondition.BackPlanSpecs && !string.IsNullOrWhiteSpace(pack.BackPlanSpecs) && !StringUtils.Equals(entity.BackPlanSpecs, pack.BackPlanSpecs))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，背板规格：{entity.BackPlanSpecs}/{pack.BackPlanSpecs}");
                }
                else if (cabinetCondition.AluFrameFactory && !string.IsNullOrWhiteSpace(pack.AluFrameFactory) && !StringUtils.Equals(entity.AluFrameFactory, pack.AluFrameFactory))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，铝框厂家：{entity.AluFrameFactory}/{pack.AluFrameFactory}");
                }
                else if (cabinetCondition.AluFrameSpecs && !string.IsNullOrWhiteSpace(pack.AluFrameSpecs) && !StringUtils.Equals(entity.AluFrameSpecs, pack.AluFrameSpecs))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，铝框规格：{entity.AluFrameSpecs}/{pack.AluFrameSpecs}");
                }
                else if (cabinetCondition.BatteryFactory && !string.IsNullOrWhiteSpace(pack.BatteryFactory) && !StringUtils.Equals(entity.BatteryFactory, pack.BatteryFactory))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，电池片厂家：{entity.BatteryFactory}/{pack.BatteryFactory}");
                }
                else if (cabinetCondition.BatterySpecs && !string.IsNullOrWhiteSpace(pack.BatterySpecs) && !StringUtils.Equals(entity.BatterySpecs, pack.BatterySpecs))
                {
                    throw new MultiLanBizException(129006, $"{configStr}，箱号：{pack.PackNo}，电池片规格：{entity.BatterySpecs}/{pack.BatterySpecs}");
                }
            }
            var cabinetPacks = packs.Select(_ => new CabinetPack
            {
                CabinetNo = model.CabinetNo,
                PackNo = _.PackNo,
                AreaCode = _.AreaCode,
                AreaName = _.AreaName,
                Location = _.Location,
                WarehouseCode = _.WarehouseCode,
                WarehouseName = _.WarehouseName,
                PackBatchNo = _.PackBatchNo,
                CreateBy = model.CreateBy,
                CreateTime = DateTime.Now
            }).ToList();

            mesDb.CabinetPacks.AddRange(cabinetPacks);
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    var components = mesDb.Components.AsNoTracking().Where(_ => packNos.Contains(_.PackNo) && _.Valid).ToList();
                    components.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.CabinetNo = entity.CabinetNo;
                        _.CabinetTime = DateTime.Now;
                        _.ModifyBy = entity.CreateBy;
                        _.ModifyTime = DateTime.Now;
                    });

                    packs.ForEach(_ =>
                    {
                        mesDb.Packs.Attach(_);
                        _.CabinetNo = entity.CabinetNo;
                        _.ModifyBy = entity.CreateBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    var storages = mesDb.Storages.AsNoTracking().Where(_ => packNos.Contains(_.PackNo) && _.Valid).ToList();
                    storages.ForEach(_ =>
                    {
                        mesDb.Storages.Attach(_);
                        _.CabinetNo = entity.CabinetNo;
                        _.ModifyBy = entity.CreateBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    mesDb.SaveChanges();

                    var users = new UserMgr().QueryUsers(new List<int> { model.CreateBy });
                    var logs = components.Select(_ => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = _.BarCode,
                        LogName = "组件拼柜",
                        LogStatus = "正常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = users.FirstOrDefault()?.TrueName,
                        LogContent = $"组件拼柜，柜号：{model.CabinetNo}",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"打包异常，打包编号：{entity.CabinetNo}，异常信息：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 获取柜列表
        /// </summary>
        /// <param name="cabinetNo">柜号</param>
        /// <returns>柜对象</returns>
        public VCabinet GetCabinet(string cabinetNo)
        {
            var entity = mesDb.Cabinets.AsNoTracking().FirstOrDefault(_ => _.CabinetNo == cabinetNo && _.Status != CabinetStatus.UnCabinet && _.Valid);
            var model = Mapper.Map<VCabinet>(entity);
            if (model == null)
            {
                return null;
            }
            model.CabinetCondition = string.IsNullOrWhiteSpace(model.OrderNo) && string.IsNullOrWhiteSpace(model.WorkOrderNo) ? null
                : new CabinetConditionMgr().GetCabinetCondition(string.Empty, model.WorkOrderNo, !StringUtils.Equals("Q1", model.QLevel) ? QLevelCondition.NotQ1 : QLevelCondition.Q1);
            model.CNCreateBy = new UserMgr().QueryUsers(new List<int> { model.CreateBy }).FirstOrDefault()?.TrueName;
            var cabinetPacks = mesDb.Packs.AsNoTracking().Where(_ => _.CabinetNo == model.CabinetNo && _.Valid).ToList();
            model.Packs = Mapper.Map<List<VPack>>(cabinetPacks);
            return model;
        }

        /// <summary>
        /// 完成拼柜
        /// </summary>
        /// <param name="model">拼柜对象</param>
        public void FinishCabinet(VCabinet model)
        {
            var entity = mesDb.Cabinets.AsNoTracking().FirstOrDefault(_ => _.CabinetNo == model.CabinetNo && _.Status == CabinetStatus.Cabineting && _.Valid);
            if (entity == null)
            {
                throw new MultiLanBizException(129003, model.CabinetNo);// 当前柜号不存在
            }
            var packCount = mesDb.CabinetPacks.AsNoTracking().Count(_ => _.CabinetNo == model.CabinetNo && _.Valid);
            if (packCount <= 0)
            {
                throw new MultiLanBizException(129004, model.CabinetNo);// 当前没有拼柜包装，无法完成拼柜
            }

            mesDb.Cabinets.Attach(entity);
            entity.Status = CabinetStatus.Normal;
            entity.FinishTime = DateTime.Now;
            entity.ModifyBy = model.ModifyBy;
            entity.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();
        }

        /// <summary>
        /// 查询装柜列表
        /// </summary>
        /// <param name="pageIndex">页面索引</param>
        /// <param name="pageSize">页面容量</param>
        /// <param name="total">总数</param>
        /// <param name="warehouseCode">仓库代码</param>
        /// <param name="cabinetBy">拼柜人</param>
        /// <returns></returns>
        public List<VCabinet> QueryCabinets(int pageIndex, int pageSize, out int total, int cabinetBy)
        {
            var query = mesDb.Cabinets.Where(_ => _.Status != CabinetStatus.UnCabinet && _.Valid);
            if (cabinetBy > 0)
            {
                query = query.Where(_ => _.CreateBy == cabinetBy);
            }
            total = query.Count();

            query = query.OrderByDescending(_ => _.PkId);
            var entities = pageSize <= 0 ? query.ToList() : query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            var models = Mapper.Map<List<VCabinet>>(entities);
            var userIds = models.Select(_ => _.CreateBy).Distinct().ToList();
            var users = new UserMgr().QueryUsers(userIds);
            models.ForEach(cabinet =>
            {
                cabinet.CNCreateBy = users.FirstOrDefault(_ => _.PkId == cabinet.CreateBy)?.TrueName;
            });
            return models;
        }

        /// <summary>
        /// 解柜单个包装
        /// </summary>
        /// <param name="model"></param>
        public void UnCabinetPack(VCabinetPack model)
        {
            var cabinetPack = mesDb.CabinetPacks.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.Valid);
            if (cabinetPack == null)
            {
                return;
            }
            var cabinet = mesDb.Cabinets.AsNoTracking().FirstOrDefault(_ => _.CabinetNo == cabinetPack.CabinetNo && _.Status != CabinetStatus.UnCabinet && _.Valid);
            if (cabinet.Status != CabinetStatus.Cabineting)
            {
                throw new MultiLanBizException(129008);//当前状态不可解柜
            }

            mesDb.CabinetPacks.Attach(cabinetPack);
            cabinetPack.Valid = false;
            cabinetPack.ModifyBy = model.ModifyBy;
            cabinetPack.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    #region 处理包装
                    var pack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.Valid);
                    if (pack != null)
                    {
                        mesDb.Packs.Attach(pack);
                        pack.CabinetNo = string.Empty;
                        pack.ModifyBy = model.ModifyBy;
                        pack.ModifyTime = DateTime.Now;
                    }
                    #endregion

                    #region 处理组件
                    var components = mesDb.Components.AsNoTracking().Where(_ => _.PackNo == model.PackNo).ToList();
                    components.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.CabinetNo = string.Empty;
                        _.CabinetTime = null;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    #endregion
                    mesDb.SaveChanges();

                    var user = new UserMgr().QueryUsers(new List<int> { model.ModifyBy }).FirstOrDefault();
                    var logs = components.Select(_ => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = _.BarCode,
                        LogName = "组件解包",
                        LogStatus = "异常",
                        OpeatorId = model.ModifyBy,
                        OpeatorName = user?.TrueName,
                        LogContent = $"单个组件解包",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"解柜单个包装失败，包装编号：{model.PackNo}，异常信息：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 解柜
        /// </summary>
        /// <param name="model">柜子</param>
        public void UnCabinet(VCabinet model)
        {
            var entity = mesDb.Cabinets.AsNoTracking().FirstOrDefault(_ => _.CabinetNo == model.CabinetNo && _.Status != CabinetStatus.UnCabinet && _.Valid);
            if (entity == null)
            {
                throw new MultiLanBizException(129003, model.CabinetNo);// "当前柜号不存在
            }

            mesDb.Cabinets.Attach(entity);
            entity.Status = CabinetStatus.UnCabinet;
            entity.ModifyBy = model.ModifyBy;
            entity.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    var cabinetPacks = mesDb.CabinetPacks.AsNoTracking().Where(_ => _.CabinetNo == model.CabinetNo && _.Valid).ToList();
                    cabinetPacks.ForEach(_ =>
                    {
                        mesDb.CabinetPacks.Attach(_);
                        _.Valid = false;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });

                    var packs = mesDb.Packs.AsNoTracking().Where(_ => _.CabinetNo == model.CabinetNo && _.Valid).ToList();
                    packs.ForEach(_ =>
                    {
                        mesDb.Packs.Attach(_);
                        _.CabinetNo = string.Empty;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });

                    var components = mesDb.Components.AsNoTracking().Where(_ => _.CabinetNo == model.CabinetNo && _.Valid).ToList();
                    components.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.CabinetTime = null;
                        _.CabinetNo = string.Empty;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    mesDb.SaveChanges();

                    var users = new UserMgr().QueryUsers(new List<int> { model.ModifyBy });
                    var logs = components.Select(_ => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = _.BarCode,
                        LogName = "组件解柜",
                        LogStatus = "异常",
                        OpeatorId = model.ModifyBy,
                        OpeatorName = users.FirstOrDefault()?.TrueName,
                        LogContent = $"组件解柜，原柜号：{model.CabinetNo}",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"解柜异常，柜号编号：{model.CabinetNo}，异常信息：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 查询拼柜记录
        /// </summary>
        /// <param name="pageIndex">页面索引</param>
        /// <param name="pageSize">页面容量</param>
        /// <param name="total">总数</param>
        /// <param name="warehouseCode">仓库代码</param>
        /// <param name="orderNo">订单号</param>
        /// <param name="workOrderNo"></param>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public List<VCabinet> QueryCabinets(int page, int limit, out int total, string warehouseCode, string orderNo, string workOrderNo, string cabinetNo, DateTime? startTime, DateTime? endTime, CabinetStatus? status)
        {
            var query = mesDb.Cabinets.Where(_ => _.Valid);

            if (!string.IsNullOrWhiteSpace(cabinetNo))
            {
                query = query.Where(_ => _.CabinetNo.Contains(cabinetNo));
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(warehouseCode))
                {
                    query = query.Where(_ => _.WarehouseCode == warehouseCode);
                }
                if (!string.IsNullOrWhiteSpace(orderNo))
                {
                    query = query.Where(_ => _.OrderNo.Contains(orderNo));
                }
                if (!string.IsNullOrWhiteSpace(workOrderNo))
                {
                    query = query.Where(_ => _.WorkOrderNo.Contains(workOrderNo));
                }
                if (startTime.HasValue && endTime.HasValue)
                {
                    query = query.Where(_ => _.CreateTime >= startTime && _.CreateTime < endTime);
                }
            }
            if (status.HasValue)
            {
                query = query.Where(_ => _.Status == status.Value);
            }
            total = query.Count();

            query = query.OrderByDescending(_ => _.PkId);
            var entities = limit <= 0 ? query.ToList() : query.Skip((page - 1) * limit).Take(limit).ToList();
            var models = Mapper.Map<List<VCabinet>>(entities);
            var userIds = models.Select(_ => _.CreateBy).Distinct().ToList();
            var users = new UserMgr().QueryUsers(userIds);
            models.ForEach(cabinet =>
            {
                cabinet.CNCreateBy = users.FirstOrDefault(_ => _.PkId == cabinet.CreateBy)?.TrueName;
            });
            return models;
        }
    }
}
